/*

This file is part of roomyak.

Copyright (C) 2008 Pixecur Technologies Incorporated (Esotera).
Visit Esotera at http://www.esoteras3.com
 
roomyak is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
roomyak is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with roomyak; see the file COPYING.  If not, write to 
Pixecur Technologies, 213-31 Peet Street, St. John's, NL, A1B 3W8. 
 
Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
 
*/

package com.datasentinel.util.concurrent;

import java.util.Stack;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.logging.Level;
import java.util.logging.Logger;

public class NamedLockWrapper implements Lock
{
	private static final long serialVersionUID = 1L;

	private String name;
	public String getName()
	{
		return name;
	}

	private String context;
	private Logger logger;
	private Level loggerLevel;
	
	private Lock lock;
	
	private Stack<Thread> threadStack = new Stack<Thread>();
	
	public NamedLockWrapper(Lock lock, String name, String context, Logger logger, Level loggerLevel)
	{
		this.lock = lock;
		this.name = name;
		this.context = context;
		this.logger = logger;
		this.loggerLevel = loggerLevel;
	}
	
	
	@Override
	public void lock()
	{
		logger.log(loggerLevel, this.name + ".LOCK(-><-); " + context + " -  Thread: [" + Thread.currentThread().getName() + "] #" + Thread.currentThread().getId());
		lock.lock();
		threadStack.push(Thread.currentThread());
	}
	
	@Override
	public void unlock()
	{
		logger.log(loggerLevel, this.name + ".UNLOCK(<- ->); " + context + " -  Thread: [" + Thread.currentThread().getName() + "] #" + Thread.currentThread().getId());
		threadStack.pop();
		lock.unlock();
	}
	
	@Override
	public boolean tryLock()
	{
		boolean result = lock.tryLock();
		if(result)
		{
			threadStack.push(Thread.currentThread());
		}
		logger.log(loggerLevel, this.name + ".TRY_LOCK(>?<) = " + result + "; " + context + " -  Thread: [" + Thread.currentThread().getName() + "] #" + Thread.currentThread().getId());
		return result;
	}
	
	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException
	{
		boolean result = lock.tryLock();
		if(result)
		{
			threadStack.push(Thread.currentThread());
		}
		
		logger.log(loggerLevel, this.name + ".TRY_LOCK(>?[" + time + " " +  unit.toString() + "] +<) = " + result + "; " + context + " -  Thread: [" + Thread.currentThread().getName() + "] #" + Thread.currentThread().getId());
		return result;
	}
	
	@Override
	public Condition newCondition()
	{
		return new NamedConditionWrapper(this, lock.newCondition(), logger, loggerLevel);
	}
	
	@Override
	public void lockInterruptibly() throws InterruptedException
	{
		logger.log(loggerLevel, this.name + ".LOCK_INTERUPT(->*<-); " + context + " -  Thread: [" + Thread.currentThread().getName() + "] #" + Thread.currentThread().getId());
		lock.lockInterruptibly();
		threadStack.push(Thread.currentThread());
	}
}
